<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分子碰撞与过渡态理论可视化</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            background: linear-gradient(135deg, #0c0e1d, #1a1f3d);
            color: #e0f7ff;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            min-height: 100vh;
            overflow: hidden;
            display: flex;
            flex-direction: column;
        }
        
        header {
            text-align: center;
            padding: 20px;
            background: rgba(0, 10, 26, 0.7);
            border-bottom: 1px solid rgba(0, 173, 255, 0.3);
            box-shadow: 0 5px 15px rgba(0, 60, 120, 0.3);
            z-index: 10;
        }
        
        h1 {
            font-size: 2.2rem;
            margin-bottom: 8px;
            background: linear-gradient(to right, #4facfe, #00f2fe);
            -webkit-background-clip: text;
            background-clip: text;
            color: transparent;
            text-shadow: 0 0 10px rgba(79, 172, 254, 0.3);
        }
        
        .subtitle {
            font-size: 1.1rem;
            opacity: 0.8;
            max-width: 800px;
            margin: 0 auto;
            line-height: 1.6;
        }
        
        .container {
            display: flex;
            flex: 1;
            padding: 20px;
            gap: 30px;
            max-width: 1600px;
            margin: 0 auto;
            width: 100%;
        }
        
        .animation-panel, .energy-panel {
            background: rgba(5, 15, 35, 0.6);
            border-radius: 15px;
            border: 1px solid rgba(0, 173, 255, 0.2);
            box-shadow: 0 8px 32px rgba(0, 30, 60, 0.3);
            backdrop-filter: blur(10px);
            overflow: hidden;
            position: relative;
        }
        
        .animation-panel {
            flex: 1.5;
            display: flex;
            flex-direction: column;
        }
        
        .energy-panel {
            flex: 1;
            display: flex;
            flex-direction: column;
        }
        
        .panel-header {
            padding: 15px 20px;
            background: rgba(0, 20, 50, 0.5);
            border-bottom: 1px solid rgba(0, 173, 255, 0.2);
            font-size: 1.3rem;
            font-weight: 600;
            display: flex;
            align-items: center;
        }
        
        .panel-header i {
            margin-right: 10px;
            color: #00c6ff;
        }
        
        .panel-content {
            flex: 1;
            position: relative;
            overflow: hidden;
        }
        
        canvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
        
        .legend {
            position: absolute;
            bottom: 20px;
            left: 20px;
            background: rgba(0, 20, 40, 0.7);
            padding: 12px 15px;
            border-radius: 10px;
            border: 1px solid rgba(0, 173, 255, 0.2);
            display: flex;
            gap: 15px;
        }
        
        .legend-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .legend-color {
            width: 18px;
            height: 18px;
            border-radius: 50%;
        }
        
        .reaction-equation {
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(0, 20, 40, 0.7);
            padding: 12px 20px;
            border-radius: 10px;
            border: 1px solid rgba(0, 173, 255, 0.2);
            font-size: 1.3rem;
            font-weight: bold;
            color: #4facfe;
        }
        
        .theory-info {
            position: absolute;
            bottom: 20px;
            left: 20px;
            right: 20px;
            background: rgba(0, 20, 40, 0.7);
            padding: 15px;
            border-radius: 10px;
            border: 1px solid rgba(0, 173, 255, 0.2);
            font-size: 0.95rem;
            line-height: 1.6;
        }
        
        .theory-info h3 {
            margin-bottom: 8px;
            color: #00c6ff;
        }
        
        .controls {
            position: absolute;
            top: 20px;
            left: 20px;
            display: flex;
            gap: 10px;
        }
        
        .control-btn {
            background: rgba(0, 40, 80, 0.7);
            color: #e0f7ff;
            border: 1px solid rgba(0, 173, 255, 0.3);
            border-radius: 30px;
            padding: 8px 15px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-size: 0.9rem;
        }
        
        .control-btn:hover {
            background: rgba(0, 80, 160, 0.7);
            box-shadow: 0 0 10px rgba(0, 173, 255, 0.5);
        }
        
        @media (max-width: 1100px) {
            .container {
                flex-direction: column;
                height: auto;
            }
            
            .animation-panel, .energy-panel {
                min-height: 500px;
            }
        }
    </style>
</head>
<body>
    <header>
        <h1>分子碰撞理论与过渡态理论</h1>
        <p class="subtitle">
        本可视化展示了化学反应中分子碰撞形成过渡态并转化为生成物的过程，以及反应过程中能量的变化。
        本页面使用AI辅助，仅供示意
        </p>
    </header>
    
    <div class="container">
        <div class="animation-panel">
            <div class="panel-header">
                ⚛️ 分子碰撞过程
            </div>
            <div class="panel-content">
                <canvas id="moleculeCanvas"></canvas>
                <div class="reaction-equation">2A + B ⇌ AB* ⇌ C</div>
                <div class="controls">
                    <button class="control-btn" id="pauseBtn">暂停</button>
                </div>
                <div class="legend">
                    <div class="legend-item">
                        <div class="legend-color" style="background: #ff6b6b;"></div>
                        <span>分子 A</span>
                    </div>
                    <div class="legend-item">
                        <div class="legend-color" style="background: #4ecdc4;"></div>
                        <span>分子 B</span>
                    </div>
                    <div class="legend-item">
                        <div class="legend-color" style="background: #ffd166;"></div>
                        <span>过渡态 AB*</span>
                    </div>
                    <div class="legend-item">
                        <div class="legend-color" style="background: #9478ff;"></div>
                        <span>生成物 C</span>
                    </div>
                </div>
            </div>
        </div>
        
        <div class="energy-panel">
            <div class="panel-header">
                📈 反应能量曲线
            </div>
            <div class="panel-content">
                <canvas id="energyCanvas"></canvas>
            </div>
        </div>
    </div>

    <script>
        // 获取Canvas元素
        const moleculeCanvas = document.getElementById('moleculeCanvas');
        const energyCanvas = document.getElementById('energyCanvas');
        
        // 设置Canvas尺寸
        function setupCanvas() {
            moleculeCanvas.width = moleculeCanvas.offsetWidth;
            moleculeCanvas.height = moleculeCanvas.offsetHeight;
            
            energyCanvas.width = energyCanvas.offsetWidth;
            energyCanvas.height = energyCanvas.offsetHeight;
        }
        
        setupCanvas();
        window.addEventListener('resize', setupCanvas);
        
        // 获取Canvas上下文
        const molCtx = moleculeCanvas.getContext('2d');
        const energyCtx = energyCanvas.getContext('2d');
        
        // 动画控制变量
        let isPaused = false;
        let reactionProgress = 0; // 0-100% 反应进度

        document.getElementById('pauseBtn').addEventListener('click', () => {
            isPaused = !isPaused;
            document.getElementById('pauseBtn').textContent = isPaused ? '继续' : '暂停';
        });
        
        // 分子类
        class Molecule {
            constructor(type, x, y, vx, vy, alpha) {
                this.type = type; // 'A', 'B', 'transition', 'C'
                this.x = x;
                this.y = y;
                this.vx = vx;
                this.vy = vy;
                this.radius = 30;
                this.color = this.getColor(1.0);
                this.alpha = alpha;

                this.init_x = x;
                this.init_y = y;
                
                this.last_x = x;
                this.last_y = y;
            }
            
            getColor(alpha = 1) {
                switch(this.type) {
                    case 'A': return `rgba(255, 107, 107, ${alpha})`;
                    case 'B': return `rgba(78, 205, 196, ${alpha})`;
                    case 'transition': return `rgba(255, 209, 102, ${alpha})`;
                    case 'C': return `rgba(148, 120, 255, ${alpha})`;
                }
            }

            draw(ctx) {
                if (this.alpha == 0)
                {
                    return;
                }
                ctx.save();
                ctx.translate(this.x, this.y);

                // 创建径向渐变（电子云效果）
                const gradient = ctx.createRadialGradient(
                    0, 0, this.radius * 0.2,
                    0, 0, this.radius
                );
                
                gradient.addColorStop(0, this.getColor(1.0*this.alpha));
                gradient.addColorStop(1, this.getColor(0.0*this.alpha));
                
                ctx.fillStyle = gradient;
                ctx.globalAlpha = this.alpha;
                
                // 绘制分子
                ctx.beginPath();
                ctx.arc(0, 0, this.radius, 0, Math.PI * 2);
                ctx.fill();
                
                // 绘制化学符号
                ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
                ctx.font = `${'14px'} Arial`;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                
                let symbol;
                switch(this.type) {
                    case 'A': symbol = 'A'; break;
                    case 'B': symbol = 'B'; break;
                    case 'transition': symbol = 'AB*'; break;
                    case 'C': symbol = 'C'; break;
                }
                
                ctx.fillText(symbol, 0, 0);
                
                ctx.restore();
            }
            
        }
        
        // 反应系统类
        class ReactionSystem {
            constructor() {
                this.molecules = [];
                this.state = 'approach'; // 'approach', 'collide', 'transition', 'product'
                this.timer = 0;
                this.localtimer = 0;
                this.centerX = moleculeCanvas.width / 2;
                this.centerY = moleculeCanvas.height / 2;
                this.dist = 0;
                
                this.initialize();
            }
            
            initialize() {
                // 创建初始分子（2个A和1个B）
                this.molecules = [];
                
                // 在屏幕外创建分子，让它们飞向中心
                const angle1 = Math.random() * Math.PI * 2;
                const angle2 = angle1 + Math.PI * 0.7;
                const angle3 = angle1 + Math.PI * 1.4;
                
                
                const distance = Math.max(moleculeCanvas.width, moleculeCanvas.height) * 0.7;
                this.dist = distance
                
                this.molecules.push(
                    new Molecule('A', 
                        this.centerX + Math.cos(angle1) * distance,
                        this.centerY + Math.sin(angle1) * distance,
                        Math.cos(angle1 + Math.PI) * 1.2,
                        Math.sin(angle1 + Math.PI) * 1.2,
                        1
                    )
                );
                
                this.molecules.push(
                    new Molecule('A', 
                        this.centerX + Math.cos(angle2) * distance,
                        this.centerY + Math.sin(angle2) * distance,
                        Math.cos(angle2 + Math.PI) * 1.2,
                        Math.sin(angle2 + Math.PI) * 1.2,
                        1
                    )
                );
                
                this.molecules.push(
                    new Molecule('B', 
                        this.centerX + Math.cos(angle3) * distance,
                        this.centerY + Math.sin(angle3) * distance,
                        Math.cos(angle3 + Math.PI) * 1,
                        Math.sin(angle3 + Math.PI) * 1,
                        1
                    )
                );
                
                this.molecules.push(
                    new Molecule('C', 
                        this.centerX,
                        this.centerY,
                        0,
                        0,
                        0
                    )
                );
                
                this.state = 'approach';
                this.timer = 0;
                this.localtimer = 0;
            }
            
            update() {
                this.timer++;
                this.localtimer++;
                
                switch(this.state) {
                    case 'approach': //0-60
                        for (let mol of this.molecules)
                        {
                            mol.x = (mol.init_x-this.centerX)*(1.05-Math.tanh(this.timer/40.0))+this.centerX;
                            mol.y = (mol.init_y-this.centerY)*(1.05-Math.tanh(this.timer/40.0))+this.centerY;
                            
                            mol.last_x = mol.x;
                            mol.last_y = mol.y;
                        }
                        
                        if (this.timer > 80) {
                            this.state = 'collide';
                            this.localtimer = 0;
                        }
                        break;
                        
                    case 'collide': //80-150
                        for (let mol of this.molecules)
                        {
                            mol.x = (mol.init_x-this.centerX)*(1.05-Math.tanh(this.timer/40.0))+this.centerX;
                            mol.y = (mol.init_y-this.centerY)*(1.05-Math.tanh(this.timer/40.0))+this.centerY;
                                                        
                            mol.last_x = mol.x;
                            mol.last_y = mol.y;
                        }

                        if (this.timer > 150) 
                        {
                            this.state = 'transition';
                            this.localtimer = 0;
                        }
                        break;
                        
                    case 'transition': //150-250
                        for (let mol of this.molecules)
                        {
                            mol.x = (mol.last_x-this.centerX)*(1-Math.tanh(this.localtimer/40.0))+this.centerX;
                            mol.y = (mol.last_y-this.centerY)*(1-Math.tanh(this.localtimer/40.0))+this.centerY;
                        }
                        
                        if (this.timer>200)
                        {
                            for (let mol of this.molecules)
                            {
                                if(mol.type == 'C')
                                {
                                    mol.alpha = Math.tanh((this.timer-200)/30);
                                }
                                else
                                {
                                    mol.alpha = 1-Math.tanh((this.timer-200)/30);
                                }
                            }
                        }
                        if (this.timer > 250)
                        {
                            this.state = 'product';
                            this.localtimer = 0;
                        }
                        break;
                        
                    case 'product': //250-400
                        // 生成物离开
                        if (this.timer > 400) {
                            this.initialize();
                        }
                        break;
                }
                
                // 更新反应进度（用于右侧能量图）
                reactionProgress = this.timer;
            }
            
            draw(ctx) {
                // 绘制分子
                if (this.state=='collide')
                {
                    const ctx = molCtx
                    
                    ctx.beginPath();
                    ctx.arc(this.centerX, this.centerY, 1.5*this.dist*(1.05-Math.tanh(this.timer/40.0)), 0, Math.PI * 2);
                    ctx.strokeStyle = '#ffd166';
                    ctx.lineWidth = 1;
                    ctx.stroke();
                    
                    ctx.fillStyle = '#ffd166';
                    ctx.font = `${'14px'} Arial`;
                    ctx.textAlign = 'center';
                    ctx.textBaseline = 'middle';
                    ctx.fillText('AB*', this.centerX+3*this.dist*(1.05-Math.tanh(this.timer/40.0)), this.centerY);
                    
                }
                for (let mol of this.molecules) 
                {
                    mol.draw(ctx);
                }
            }
        }
        
        // 创建反应系统
        const reactionSystem = new ReactionSystem();
        
        
        function activate_func(x)
        {
            //return Math.sin(Math.PI*x)-0.4*x+0.5;
            return 0.5+0*x+10*x**2-21.6*x**3+11.2*x**4;
        }
        
        
        // 绘制能量曲线
        function drawEnergyCurve() {
            const ctx = energyCtx;
            const width = energyCanvas.width;
            const height = energyCanvas.height;
            const padding = 50;
            
            // 清除画布
            ctx.clearRect(0, 0, width, height);
                        
            // 绘制坐标轴
            ctx.strokeStyle = '#4facfe';
            ctx.lineWidth = 2;
            
            // X轴
            ctx.beginPath();
            ctx.moveTo(padding, height - padding);
            ctx.lineTo(width - padding, height - padding);
            ctx.stroke();
            
            // Y轴
            ctx.beginPath();
            ctx.moveTo(padding, height - padding);
            ctx.lineTo(padding, padding);
            ctx.stroke();
            
            // 轴标签
            ctx.fillStyle = '#e0f7ff';
            ctx.font = '12px Arial';
            ctx.textAlign = 'center';
            
            // X轴标签
            ctx.fillText('反应进程', width / 2, height - 10);
            ctx.fillText('反应物', padding, height - 20);
            ctx.fillText('过渡态', padding + (width - padding * 2) * 0.5, height - 20);
            ctx.fillText('生成物', width - padding, height - 20);
            
            // Y轴标签
            ctx.save();
            ctx.translate(15, height / 2);
            ctx.rotate(-Math.PI / 2);
            ctx.fillText('能量', 0, 0);
            ctx.restore();
            
            // 绘制能量曲线
            ctx.strokeStyle = '#00f2fe';
            ctx.lineWidth = 3;
            ctx.beginPath();
            
            const startX = padding;
            const startY = height - padding;
            const endX = width - padding;
            const endY = height - padding - 80;
            const curve_width = (width-4*padding);
            const scale_factor = 0.5*height;
            
            let _act_peak = 0;
            
            // 曲线到过渡态（峰值）
            for (let i = 0;i<=19;i++)
            {
                n = curve_width/20;
                x = startX+n*i;
                ctx.moveTo(startX + padding + i*n,      startY - scale_factor*activate_func(i/20));
                ctx.lineTo(startX + padding + (i+1)*n , startY - scale_factor*activate_func((i+1)/20));
                
                if (activate_func(i/20) > _act_peak)
                {
                    _act_peak = activate_func(i/20);
                }
            }
            ctx.stroke();
            
            let act_start = activate_func(0);
            let act_peak  = _act_peak;
            let act_end   = activate_func(1);
            
            //反应物能量 (2A+B)
            ctx.strokeStyle = 'rgba(255, 100, 100, 0.7)';
            ctx.setLineDash([5, 3]);
            ctx.beginPath();
            ctx.moveTo(startX, startY - scale_factor*act_start);
            ctx.lineTo(endX,   startY - scale_factor*act_start);
            ctx.stroke();
            ctx.setLineDash([]);
            
            ctx.fillText('2A+B', 2*padding, startY - scale_factor*act_start+20);
            
            //过渡态能量 (AB*)
            ctx.strokeStyle = 'rgba(255, 100, 100, 0.7)';
            ctx.setLineDash([5, 3]);
            ctx.beginPath();
            ctx.moveTo(startX, startY - scale_factor*act_peak);
            ctx.lineTo(endX,   startY - scale_factor*act_peak);
            ctx.stroke();
            ctx.setLineDash([]);
            
            ctx.fillText('AB*', 2*padding+curve_width/2-10, startY - scale_factor*act_peak-20);
            
            //生成物能量 (C)
            ctx.strokeStyle = 'rgba(255, 100, 100, 0.7)';
            ctx.setLineDash([5, 3]);
            ctx.beginPath();
            ctx.moveTo(startX, startY - scale_factor*act_end);
            ctx.lineTo(endX,   startY - scale_factor*act_end);
            ctx.stroke();
            ctx.setLineDash([]);
            
            ctx.fillText('C', 2*padding+curve_width, startY - scale_factor*act_end+20);
            
            const arrowSize = 8;
            
            // 绘制活化能箭头（从反应物到过渡态）
            ctx.strokeStyle = 'rgba(0, 0, 255, 0.7)';
            ctx.fillStyle = 'rgba(0, 0, 255, 0.7)';
            ctx.beginPath();
            // 垂直线
            ctx.moveTo(startX+padding, startY - scale_factor*act_start);
            ctx.lineTo(startX+padding, startY - scale_factor*act_peak);
            // 箭头头部
            ctx.moveTo(startX+padding, startY - scale_factor*act_peak);
            ctx.lineTo(startX+padding -arrowSize, startY - scale_factor*act_peak + arrowSize);
            ctx.moveTo(startX+padding, startY - scale_factor*act_peak);
            ctx.lineTo(startX+padding +arrowSize, startY - scale_factor*act_peak + arrowSize);
            ctx.stroke();
            ctx.fillText('活化能', startX+padding, startY - scale_factor*(act_peak+act_start)/2);

            // 绘制生成能箭头（从反应物到生成物）
            ctx.strokeStyle = 'rgba(0, 150, 0, 0.7)';
            ctx.fillStyle = 'rgba(0, 150, 0, 0.7)';
            ctx.beginPath();
            // 垂直线
            ctx.moveTo(startX+curve_width, startY - scale_factor*act_start);
            ctx.lineTo(startX+curve_width, startY - scale_factor*act_end);
            // 箭头头部        
            ctx.moveTo(startX+curve_width, startY - scale_factor*act_end);
            ctx.lineTo(startX+curve_width-arrowSize, startY - scale_factor*act_end - arrowSize);
            ctx.moveTo(startX+curve_width, startY - scale_factor*act_end);
            ctx.lineTo(startX+curve_width+arrowSize, startY - scale_factor*act_end - arrowSize);
            ctx.stroke();
            ctx.fillText('生成能', startX+curve_width, startY - scale_factor*(act_start+act_end)/2);


            // 绘制发光点（反应进度指示器）
            const progress = reactionProgress;
            let progressX = 0, progressY = 0;
            let t = 0;
            t = 0;
            
            if(progress < 30)
            {
                t = 0;
            }
            else if (progress <= 150) 
            {
                t = 1/2*(progress-30)/(150-30);
            }
            else if (progress <= 250)
            {
                t = 1/2+1/2*(progress-150)/100;
            }
            else
            {
                t = 1;
            }
            progressX = startX + padding + curve_width*t;
            progressY = startY - scale_factor*activate_func(t);
            
            // 发光效果
            const gradient = ctx.createRadialGradient(
                progressX, progressY, 0,
                progressX, progressY, 20
            );
            gradient.addColorStop(0, 'rgba(255, 255, 200, 1)');
            gradient.addColorStop(1, 'rgba(255, 255, 200, 0)');
            
            ctx.fillStyle = gradient;
            ctx.beginPath();
            ctx.arc(progressX, progressY, 20, 0, Math.PI * 2);
            ctx.fill();
            
            // 中心点
            ctx.fillStyle = '#ffffff';
            ctx.beginPath();
            ctx.arc(progressX, progressY, 5, 0, Math.PI * 2);
            ctx.fill();
        }
        
        // 动画循环
        function animate() {
            if (!isPaused) {
                // 清除分子画布
                molCtx.clearRect(0, 0, moleculeCanvas.width, moleculeCanvas.height);

                // 更新和绘制反应系统
                reactionSystem.update();
                reactionSystem.draw(molCtx);
                
                // 绘制能量曲线
                drawEnergyCurve();
            }
            
            requestAnimationFrame(animate);
        }
        
        // 启动动画
        animate();
    </script>
</body>
</html>
